package com.zhixing.service.parse;

import com.zhixing.model.SwaggerDefinitionModelAttr;
import com.zhixing.common.ISwaggerConstants;
import com.zhixing.utils.StrUtils;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.util.*;

/**
 * Swagger definitions 字段 解析器
 *
 * <p> 该字段内容：包含所有定义的 MODEL 对象结构定义数据 </p>
 *
 * @author zhixing
 */
public class SwaggerDefinitionsDefinitionsParser implements SwaggerParser{

    /** definitions 解析返回结果 **/
    @Getter
    private Map<String, SwaggerDefinitionModelAttr>     swaggerModelAttrMapResult;

    /** swagger json 解析后的所有 map数据 **/
    @Getter
    private Map<String, Object>                         allMap;

    private SwaggerDefinitionsDefinitionsParser(){}

    public static SwaggerDefinitionsDefinitionsParser.Builder createBuild(){
        return  new SwaggerDefinitionsDefinitionsParser.Builder();
    }

    public static class Builder{
        private SwaggerDefinitionsDefinitionsParser parser;
        public Builder(){
            this.parser = new SwaggerDefinitionsDefinitionsParser();
        }

        public SwaggerDefinitionsDefinitionsParser.Builder allMap(Map<String, Object> allMap){
            this.parser.allMap = allMap;
            return this;
        }

        public SwaggerDefinitionsDefinitionsParser build(){
            return this.parser;
        }
    }

    @Override
    public SwaggerDefinitionsDefinitionsParser parse() throws IOException {
        doParse();
        return this;
    }

    private void doParse() throws IOException {
        Map<String, Map<String, Object>> definitions = (Map<String, Map<String, Object>>) allMap.get(ISwaggerConstants.DEFINITIONS);
        swaggerModelAttrMapResult = new HashMap<>(256);
        if (definitions != null) {
            Iterator<String> modelNameIt = definitions.keySet().iterator();
            while (modelNameIt.hasNext()) {
                String modeName = modelNameIt.next();
                getAndPutModelAttr(definitions, swaggerModelAttrMapResult, modeName);
            }
        }
    }

    /**
     * 递归生成ModelAttr
     * 对$ref类型设置具体属性
     */
    private SwaggerDefinitionModelAttr getAndPutModelAttr(Map<String, Map<String, Object>> swaggerMap, Map<String, SwaggerDefinitionModelAttr> resMap, String modeName) {
        SwaggerDefinitionModelAttr modeAttr;
        if ((modeAttr = resMap.get(ISwaggerConstants.IDEFINITIONS.ITEMS_REF_PREFIX + modeName)) == null) {
            modeAttr = new SwaggerDefinitionModelAttr();
            resMap.put(ISwaggerConstants.IDEFINITIONS.ITEMS_REF_PREFIX + modeName, modeAttr);
        } else if (modeAttr.isCompleted()) {
            return resMap.get(ISwaggerConstants.IDEFINITIONS.ITEMS_REF_PREFIX + modeName);
        }
        Map<String, Object> modeProperties = (Map<String, Object>) swaggerMap.get(modeName).get(ISwaggerConstants.IDEFINITIONS.PROPERTIES);
        if (modeProperties == null) {
            return null;
        }

        List<SwaggerDefinitionModelAttr> attrList = getModelAttrs(swaggerMap, resMap, modeAttr, modeProperties);
        List allOf = (List) swaggerMap.get(modeName).get(ISwaggerConstants.IDEFINITIONS.ALL_OF);
        if(allOf!=null){
            for (int i = 0; i < allOf.size(); i++) {
                Map c = (Map) allOf.get(i);
                if(c.get(ISwaggerConstants.IDEFINITIONS.ITEMS_REF)!=null){
                    String refName = c.get(ISwaggerConstants.IDEFINITIONS.ITEMS_REF).toString();
                    //截取 #/definitions/ 后面的
                    String clsName = refName.substring(14);
                    Map<String, Object> modeProperties1 = (Map<String, Object>) swaggerMap.get(clsName).get(ISwaggerConstants.IDEFINITIONS.PROPERTIES);
                    List<SwaggerDefinitionModelAttr> attrList1 = getModelAttrs(swaggerMap, resMap, modeAttr, modeProperties1);
                    if(attrList1!=null && attrList!=null){
                        attrList.addAll(attrList1);
                    }else if(attrList==null && attrList1!=null){
                        attrList = attrList1;
                    }
                }
            }
        }

        Object title = swaggerMap.get(modeName).get(ISwaggerConstants.IDEFINITIONS.TITLE);
        Object description = swaggerMap.get(modeName).get(ISwaggerConstants.IDEFINITIONS.DESC);
        modeAttr.setClassName(title == null ? "" : title.toString());
        modeAttr.setDescription(description == null ? "" : description.toString());
        modeAttr.setProperties(attrList);
        return modeAttr;
    }

    private List<SwaggerDefinitionModelAttr> getModelAttrs(Map<String, Map<String, Object>> swaggerMap, Map<String, SwaggerDefinitionModelAttr> resMap, SwaggerDefinitionModelAttr modeAttr, Map<String, Object> modeProperties) {
        Iterator<Map.Entry<String, Object>> mIt = modeProperties.entrySet().iterator();

        List<SwaggerDefinitionModelAttr> attrList = new ArrayList<>();

        //解析属性
        while (mIt.hasNext()) {
            Map.Entry<String, Object> mEntry = mIt.next();
            Map<String, Object> attrInfoMap = (Map<String, Object>) mEntry.getValue();
            SwaggerDefinitionModelAttr child = new SwaggerDefinitionModelAttr();
            child.setName(mEntry.getKey());
            child.setType((String) attrInfoMap.get(ISwaggerConstants.IDEFINITIONS.TYPE));
            /*if (attrInfoMap.get("format") != null) {
                child.setType(child.getType() + "(" + attrInfoMap.get("format") + ")");
            }*/
            child.setType(StringUtils.defaultIfBlank(child.getType(), "object"));

            Object ref = attrInfoMap.get(ISwaggerConstants.IDEFINITIONS.ITEMS_REF);
            Object items = attrInfoMap.get(ISwaggerConstants.IDEFINITIONS.ITEMS);
            if (ref != null || (items != null && (ref = ((Map) items).get(ISwaggerConstants.IDEFINITIONS.ITEMS_REF)) != null)) {
                String refName = ref.toString();
                //截取 #/definitions/ 后面的
                String clsName = refName.substring(14);

                // 时间类型，使用字符串显示
                if(StringUtils.isNotBlank(clsName) && !clsName.equalsIgnoreCase("LocalDateTime") && !clsName.equalsIgnoreCase("LocalDate")){
                    modeAttr.setCompleted(true);
                    SwaggerDefinitionModelAttr refModel = getAndPutModelAttr(swaggerMap, resMap, clsName);
                    if (refModel != null) {
                        child.setProperties(refModel.getProperties());
                    }
                    child.setType(StrUtils.contractStr(child.getType(),":",clsName));
                }else{
                    child.setType("string");
                }
            }

            child.setDescription((String) attrInfoMap.get(ISwaggerConstants.IDEFINITIONS.DESC));
            attrList.add(child);
        }
        return attrList;
    }
}
